/**
 ****************************************************************************************************
 * @file        usart.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2020-04-17
 * @brief       串口初始化代码(一般是串口1)，支持printf
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 STM32F103开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 * 修改说明
 * V1.0 20200417
 * 第一次发布
 *
 ****************************************************************************************************
 */

#include "./PORT/port.h"
#include "../System/config.h"
#include "stdio.h"

void (*g_usart_callback_funs[6 + 1])(uint8_t);

/*  接收状态
 *  bit15，      接收完成标志
 *  bit14，      接收到0x0d
 *  bit13~0，    接收到的有效字节数目
 */
uint16_t g_usart1_rx_sta = 0;

int fputc(int ch, FILE *f)
{
#if CFG_DEBUG_UART_ID == 1

    while ((USART1->SR & 0X40) == 0)
        ;                     /* 等待上一个字符发送完成 */
    USART1->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */

#elif CFG_DEBUG_UART_ID == 2

    while ((USART2->SR & 0X40) == 0)
        ;                     /* 等待上一个字符发送完成 */
    USART2->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */

#elif CFG_DEBUG_UART_ID == 3

    while ((USART3->SR & 0X40) == 0)
        ;                     /* 等待上一个字符发送完成 */
    USART3->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */

#elif CFG_DEBUG_UART_ID == 4

    while ((UART4->SR & 0X40) == 0)
        ;                    /* 等待上一个字符发送完成 */
    UART4->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */

#elif CFG_DEBUG_UART_ID == 5

    while ((UART5->SR & 0X40) == 0)
        ;                    /* 等待上一个字符发送完成 */
    UART5->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */

#elif CFG_DEBUG_UART_ID == 6

    while ((USART6->SR & 0X40) == 0)
        ;                     /* 等待上一个字符发送完成 */
    USART6->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */

#endif

    return ch;
}

/**
 * @brief       串口初始化
 * @param       usartx:串口号, 1~6
 * @param       baudrate:波特率
 * @param       txpin:发送引脚
 * @param       rxpin:接收引脚
 * @param       is_rx:是否使能接收
 * @retval      无
 * */
void usart_init(uint8_t usartx, uint32_t baudrate, uint8_t txpin, uint8_t rxpin, uint8_t is_rx)
{
    uint32_t sclk, temp, irqn;

    USART_TypeDef *USART_UX;

    if (usartx == 1)
    {
        USART_UX = USART1;
        RCC->APB2ENR |= 1 << 4;
        sclk = 84;
        // 串口1 和 串口6 的时钟源来自: rcc_pclk2 = 84Mhz
        // 串口2 - 5 / 7 / 8 的时钟源来自: rcc_pclk1 = 42Mhz
        irqn = USART1_IRQn;
    }
    else if (usartx == 2)
    {
        USART_UX = USART2;
        RCC->APB1ENR |= 1 << 17;
        sclk = 42;
        irqn = USART2_IRQn;
    }
    else if (usartx == 3)
    {
        USART_UX = USART3;
        RCC->APB1ENR |= 1 << 18;
        sclk = 42;
        irqn = USART3_IRQn;
    }
    else if (usartx == 4)
    {
        USART_UX = UART4;
        RCC->APB1ENR |= 1 << 19;
        sclk = 42;
        irqn = UART4_IRQn;
    }
    else if (usartx == 5)
    {
        USART_UX = UART5;
        RCC->APB1ENR |= 1 << 20;
        sclk = 42;
        irqn = UART5_IRQn;
    }
    else if (usartx == 6)
    {
        USART_UX = USART6;
        RCC->APB2ENR |= 1 << 5;
        sclk = 84;
        irqn = USART6_IRQn;
    }

    temp = (sclk * 1000000 + baudrate / 2) / baudrate; /* 得到BRR, 采用四舍五入计算 */

    /* 波特率设置 */
    USART_UX->BRR = temp;     /* 波特率设置 */
    USART_UX->CR1 = 0;        /* 清零CR1寄存器 */
    USART_UX->CR1 |= 0 << 12; /* 设置M = 0, 选择8位字长 */
    USART_UX->CR1 |= 0 << 15; /* 设置OVER8 = 0, 16倍过采样 */
    USART_UX->CR1 |= 1 << 3;  /* 串口发送使能 */

    if (is_rx == 1) /* 如果使能了接收 */
    {
        /* 使能接收中断 */
        USART_UX->CR1 |= 1 << 2;      /* 串口接收使能 */
        USART_UX->CR1 |= 1 << 5;      /* 接收缓冲区非空中断使能 */
        sys_nvic_init(3, 3, irqn, 2); /* 组2，最低优先级 */
    }

    USART_UX->CR1 |= 1 << 13; /* UE = 1, 串口使能 */

    gpio_pin_init(txpin, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_HIGH, GPIO_PUPD_PU);

    gpio_pin_init(rxpin, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_HIGH, GPIO_PUPD_PU);

    if (usartx == 1 || usartx == 2 || usartx == 3)
    {
        gpio_af_set(txpin, 7);
        gpio_af_set(rxpin, 7);
    }
    else if (usartx == 4 || usartx == 5 || usartx == 6)
    {
        gpio_af_set(txpin, 8);
        gpio_af_set(rxpin, 8);
    }
}

/**
 * @brief       串口发送一个字节
 * @param       usartx:串口号, 1~6
 * @param       data:要发送的数据
 * @retval      无
 * */
void usart_send_byte(uint8_t usartx, uint8_t data)
{
    USART_TypeDef *USART_UX;

    if (usartx == 1)
        USART_UX = USART1;
    else if (usartx == 2)
        USART_UX = USART2;
    else if (usartx == 3)
        USART_UX = USART3;
    else if (usartx == 4)
        USART_UX = UART4;
    else if (usartx == 5)
        USART_UX = UART5;
    else if (usartx == 6)
        USART_UX = USART6;

    USART_UX->DR = data;

    while ((USART_UX->SR & 0X40) == 0)
        ; /* 等待上一个字符发送完成 */
}

/**
 * @brief       串口发送多个字节
 * @param       usartx:串口号, 1~6
 * @param       data:要发送的数据
 * @param       len:要发送的数据长度
 * @retval      无
 * */
void usart_send_data(uint8_t usartx, uint8_t *data, uint16_t len)
{
    uint16_t i;

    for (i = 0; i < len; i++)
    {
        usart_send_byte(usartx, data[i]);
    }
}

/**
 * @brief       串口中断回调函数注册
 * @param       callback:回调函数
 * @retval      无
 */
void usart_iqr_callback_register(uint8_t usart_id, void (*callback)(uint8_t))
{
    g_usart_callback_funs[usart_id] = callback;
}

/**
 * @brief       串口中断回调函数注销
 * @param       callback:回调函数
 * @retval      无
 */
void usart_iqr_callback_deregister(uint8_t usart_id, void (*callback)(uint8_t))
{
    g_usart_callback_funs[usart_id] = NULL;
}

/**
 * @brief       串口1中断服务函数
 * @param       无
 * @retval      无
 */
void USART1_IRQHandler(void)
{
    uint8_t rxdata;

    if (USART1->SR & (1 << 5)) /* 接收到数据 */
    {
        rxdata = USART1->DR;
        if (g_usart_callback_funs[1] != NULL)
            g_usart_callback_funs[1](rxdata); /* 调用回调函数 */
    }
}

/**
 * @brief       串口2中断服务函数
 * @param       无
 * @retval      无
 */
void USART2_IRQHandler(void)
{
    uint8_t rxdata;

    if (USART2->SR & (1 << 5)) /* 接收到数据 */
    {
        rxdata = USART2->DR;
        if (g_usart_callback_funs[2] != NULL)
            g_usart_callback_funs[2](rxdata); /* 调用回调函数 */
    }
}

/**
 * @brief       串口3中断服务函数
 * @param       无
 * @retval      无
 * */
void USART3_IRQHandler(void)
{
    uint8_t rxdata;

    if (USART3->SR & (1 << 5)) /* 接收到数据 */
    {
        rxdata = USART3->DR;
        if (g_usart_callback_funs[3] != NULL)
            g_usart_callback_funs[3](rxdata); /* 调用回调函数 */
    }
}

/**
 * @brief       串口4中断服务函数
 * @param       无
 * @retval      无
 * */
void UART4_IRQHandler(void)
{
    uint8_t rxdata;

    if (UART4->SR & (1 << 5)) /* 接收到数据 */
    {
        rxdata = UART4->DR;
        if (g_usart_callback_funs[4] != NULL)
            g_usart_callback_funs[4](rxdata); /* 调用回调函数 */
    }
}

/**
 * @brief       串口5中断服务函数
 * @param       无
 * @retval      无
 * */
void UART5_IRQHandler(void)
{
    uint8_t rxdata;

    if (UART5->SR & (1 << 5)) /* 接收到数据 */
    {
        rxdata = UART5->DR;
        if (g_usart_callback_funs[5] != NULL)
            g_usart_callback_funs[5](rxdata); /* 调用回调函数 */
    }
}

/**
 * @brief       串口6中断服务函数
 * @param       无
 * @retval      无
 * */
void USART6_IRQHandler(void)
{
    uint8_t rxdata;

    if (USART6->SR & (1 << 5)) /* 接收到数据 */
    {
        rxdata = USART6->DR;
        if (g_usart_callback_funs[6] != NULL)
            g_usart_callback_funs[6](rxdata); /* 调用回调函数 */
    }
}
